package com.airwallex.strategy.impl;

import com.airwallex.util.constant.ProjectConstants;
import com.airwallex.model.ExpParam;
import com.airwallex.strategy.CalculateStrategy;
import com.airwallex.util.CalculatorUtils;
import com.airwallex.util.exception.InsufficientParamException;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.List;
import java.util.Stack;

public class SqrtStrategy implements CalculateStrategy {
    @Override
    public void execCalc(Stack<ExpParam> numbers, Stack<List<ExpParam>> logs) {
        if (numbers.size() > 0) {
            BigDecimal opnd = numbers.pop().getNum();

            //牛顿迭代
            BigDecimal base2 = BigDecimal.valueOf(2);
            int precision = 100;
            MathContext mc = new MathContext(precision, RoundingMode.HALF_UP);
            BigDecimal deviation = opnd;
            int count = 0;
            //Xn+1 = (Xn + C/Xn) / 2.0
            while (count < precision) {
                deviation = (deviation.add(opnd.divide(deviation, mc))).divide(base2, mc);
                count++;
            }
            BigDecimal result = deviation
                    .setScale(ProjectConstants.RESULT_SCALE, ProjectConstants.ROUNDING_MODE);

            ExpParam resultParam = ExpParam.builder()
                    .content(result.toString())
                    .num(result)
                    .pos(-1)
                    .isNumber(true)
                    .build();
            numbers.push(resultParam);
            CalculatorUtils.addLog(numbers, logs);
        } else {
            throw new InsufficientParamException("insucient parameters !");
        }
    }

}
